Popular Searches
Popular Course Categories
Popular Courses

Sorting and Searching Collections Using Collections Utilities

Sorting and Searching Collections Using Collections Utilities

Maps, Iterators, and Collection Utilities

Sorting and Searching Collections Using Collections Utilities in Java

Course: Core Java Training

Topic: Sorting and Searching Collections Using Collections Utilities

Course Link: Core Java Training Course

Demo Link: Register for a Free Course Demo

JustAcademy Website: Visit JustAcademy


1. Introduction to Sorting and Searching Collections

Java Collections Framework provides classes and interfaces to store, organize, and manipulate groups of objects. While working with collections, developers frequently need to arrange elements in a particular order or find specific elements efficiently.

The java.util.Collections class provides several static utility methods for working with collections. Two important operations are sorting and searching. Sorting arranges elements according to a defined order, while searching helps locate an element or determine whether it exists.

For example, an application may sort student names alphabetically, arrange employee salaries from highest to lowest, or search for a product price in a sorted list.

Learning Objectives

  • Understand the purpose of the Collections utility class.
  • Learn how to sort lists using natural ordering.
  • Sort collections using custom comparators.
  • Understand ascending and descending order.
  • Search sorted lists using Collections.binarySearch().
  • Use utility methods such as min(), max(), reverse(), and shuffle().
  • Recognize common errors and follow best practices.

2. Understanding the Collections Utility Class

The Collections class belongs to the java.util package. It contains static methods that operate on collections, especially lists, and provides algorithms for sorting, searching, reversing, shuffling, and finding minimum or maximum values.

Import the class using:

import java.util.Collections;

To work with lists, you will commonly also need:

import java.util.ArrayList;
import java.util.List;

Common Collections Utility Methods

Method Purpose
Collections.sort(list) Sorts elements using their natural ordering.
Collections.sort(list, comparator) Sorts elements according to a custom comparator.
Collections.binarySearch(list, key) Searches a list using binary search.
Collections.reverse(list) Reverses the current order of list elements.
Collections.shuffle(list) Randomly rearranges list elements.
Collections.min(collection) Finds the smallest element under natural ordering.
Collections.max(collection) Finds the largest element under natural ordering.
Collections.frequency(collection, value) Counts occurrences of a specified value.
Collections.swap(list, i, j) Swaps elements at two indexes.

3. Understanding Natural Ordering

Natural ordering is the default order defined by a type's Comparable implementation. For common Java types, integers are ordered numerically and strings are ordered lexicographically, based on their character values.

Examples of natural ordering:

  • Numbers: 10, 20, 30, 40
  • Strings: "Apple", "Banana", "Mango"
  • Characters: generally ordered by their character values.

When sorting objects using natural ordering, the elements must be mutually comparable. For custom classes, implement Comparable or provide a Comparator.

4. Sorting a List in Ascending Order

The Collections.sort(list) method arranges elements in ascending natural order. The list must support the modifications required by the sorting operation.

Example: Sorting Integers

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class AscendingSortExample {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();

        numbers.add(50);
        numbers.add(10);
        numbers.add(40);
        numbers.add(20);
        numbers.add(30);

        System.out.println("Before sorting: " + numbers);

        Collections.sort(numbers);

        System.out.println("After sorting: " + numbers);
    }
}

Output:

Before sorting: [50, 10, 40, 20, 30]
After sorting: [10, 20, 30, 40, 50]

Explanation

  1. An ArrayList stores the integer values.
  2. The values are initially stored in insertion order.
  3. Collections.sort(numbers) sorts the list in ascending natural order.
  4. The same list contains the sorted values after the method completes.

Important: Sorting changes the list itself; it does not automatically create a separate sorted copy.

5. Sorting Strings Alphabetically

Strings can also be sorted using their natural ordering. This is useful when displaying names, product labels, city names, or other text values alphabetically according to Java's string comparison rules.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class StringSortExample {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();

        names.add("Rahul");
        names.add("Amit");
        names.add("Priya");
        names.add("Neha");

        Collections.sort(names);

        System.out.println(names);
    }
}

Output:

[Amit, Neha, Priya, Rahul]

Java's natural string ordering is case-sensitive and is based on character values. If an application needs case-insensitive ordering or locale-specific alphabetical rules, use an appropriate comparator or locale-aware collation utility.

6. Sorting in Descending Order

Descending order arranges elements from largest to smallest or from later to earlier according to the chosen ordering. For naturally comparable values, Collections.reverseOrder() provides a comparator that reverses natural ordering.

Example: Descending Number Sort

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class DescendingSortExample {
    public static void main(String[] args) {
        List<Integer> numbers =
                new ArrayList<>(List.of(10, 50, 20, 40, 30));

        Collections.sort(numbers, Collections.reverseOrder());

        System.out.println(numbers);
    }
}

Output:

[50, 40, 30, 20, 10]

Note: List.of() creates an unmodifiable list, so the example wraps it in an ArrayList before sorting.

7. Sorting Using a Custom Comparator

Sometimes natural ordering does not match the application's requirements. For example, an employee list may need to be sorted by salary, age, name, or joining date. A Comparator defines a custom comparison rule.

The Collections.sort(list, comparator) method sorts a list according to the provided comparator.

Example: Sorting Strings by Length

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class CustomComparatorExample {
    public static void main(String[] args) {
        List<String> words =
                new ArrayList<>(List.of("Java", "Collections", "API", "Code"));

        Comparator<String> byLength =
                Comparator.comparingInt(String::length);

        Collections.sort(words, byLength);

        System.out.println(words);
    }
}

Output:

[API, Java, Code, Collections]

The comparator compares strings by length. Strings with equal lengths may appear in their original relative order because the sorting operation is stable. If a specific order is required for equal-length words, add a secondary comparison:

Comparator<String> byLengthThenName =
        Comparator.comparingInt(String::length)
                  .thenComparing(Comparator.naturalOrder());

8. Sorting Custom Objects

In real-world applications, collections often contain objects rather than simple values. Consider an application that stores employee records. Each employee has an ID, a name, and a salary. To sort these objects, you can define a comparator for the required field.

Example: Sorting Employees by Salary

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class Employee {
    private final int id;
    private final String name;
    private final double salary;

    Employee(int id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public String toString() {
        return id + " " + name + " " + salary;
    }
}

public class EmployeeSortExample {
    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();

        employees.add(new Employee(1, "Amit", 45000));
        employees.add(new Employee(2, "Priya", 60000));
        employees.add(new Employee(3, "Rahul", 50000));

        Collections.sort(
            employees,
            Comparator.comparingDouble(Employee::getSalary)
        );

        employees.forEach(System.out::println);
    }
}

Output:

1 Amit 45000.0
3 Rahul 50000.0
2 Priya 60000.0

To sort salaries from highest to lowest, use:

employees.sort(
    Comparator.comparingDouble(Employee::getSalary).reversed()
);

9. Using List.sort() as an Alternative

Modern Java also provides the List.sort() method. It accepts a comparator and can be used instead of Collections.sort() when sorting a list.

List<Integer> numbers =
        new ArrayList<>(List.of(40, 10, 30, 20));

numbers.sort(null); // Natural ordering
System.out.println(numbers);

numbers.sort(Collections.reverseOrder());
System.out.println(numbers);

Output:

[10, 20, 30, 40]
[40, 30, 20, 10]

Use either approach according to project conventions and readability. Both approaches sort the list in place.

10. Searching Collections Using Binary Search

Searching means locating an element in a collection. Java provides several ways to search, including sequential searching with loops or contains() and binary searching with Collections.binarySearch().

Binary search repeatedly divides a sorted search range into smaller parts. It compares the target with the middle element and continues searching in the appropriate half.

How Binary Search Works

  1. Start with a list sorted in ascending order according to the intended ordering.
  2. Find the middle element of the current search range.
  3. Compare the middle element with the target value.
  4. If they match, return the index.
  5. If the target is smaller, continue in the lower half; if larger, continue in the upper half.
  6. Repeat until the value is found or the search range becomes empty.

For a random-access list such as an ArrayList, binary search generally performs in logarithmic time, commonly described as O(log n).

11. Using Collections.binarySearch()

The Collections.binarySearch() method searches a list for a specified key. The list must already be sorted according to the same ordering used by the search method. Searching an unsorted list produces undefined results.

Example: Searching for a Number

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class BinarySearchExample {
    public static void main(String[] args) {
        List<Integer> numbers =
                new ArrayList<>(List.of(50, 10, 40, 20, 30));

        Collections.sort(numbers);

        int index = Collections.binarySearch(numbers, 30);

        System.out.println("Sorted list: " + numbers);
        System.out.println("Index of 30: " + index);
    }
}

Output:

Sorted list: [10, 20, 30, 40, 50]
Index of 30: 2

Indexes start at zero, so the value 30 is located at index 2.

12. Searching for an Element That Does Not Exist

If the target is not found, Collections.binarySearch() returns a negative value. Specifically, it returns -(insertion point) - 1. The insertion point is where the key could be inserted while maintaining the list's ordering.

List<Integer> numbers =
        new ArrayList<>(List.of(10, 20, 30, 40, 50));

int result = Collections.binarySearch(numbers, 35);

if (result >= 0) {
    System.out.println("Found at index: " + result);
} else {
    int insertionPoint = -result - 1;
    System.out.println("Not found.");
    System.out.println("Insertion point: " + insertionPoint);
}

Output:

Not found.
Insertion point: 3

The value 35 belongs between 30 and 40, at index 3. The negative return value itself is not a normal list index.

13. Binary Search with a Comparator

When a list is sorted using a custom comparator, search it using the same comparator. The sorting and searching orders must agree.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ReverseBinarySearchExample {
    public static void main(String[] args) {
        List<Integer> numbers =
                new ArrayList<>(List.of(10, 50, 20, 40, 30));

        Collections.sort(numbers, Collections.reverseOrder());

        int index = Collections.binarySearch(
                numbers, 30, Collections.reverseOrder()
        );

        System.out.println(numbers);
        System.out.println("Index: " + index);
    }
}

Output:

[50, 40, 30, 20, 10]
Index: 2

Using the natural-order search on this reverse-sorted list would violate the search method's ordering requirement.

14. Linear Search vs. Binary Search

Feature Linear Search Binary Search
Approach Checks elements one by one. Repeatedly halves the search range.
Sorting required No. Yes, according to the same ordering.
Typical time complexity O(n) O(log n) for random-access lists.
Java examples Loop, contains(), or indexOf(). Collections.binarySearch().
Best use Small or unsorted collections. Sorted lists searched repeatedly.

15. Finding Minimum and Maximum Elements

The Collections.min() and Collections.max() methods find the smallest and largest elements under natural ordering or a supplied comparator.

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class MinMaxExample {
    public static void main(String[] args) {
        List<Integer> numbers =
                Arrays.asList(25, 10, 80, 45, 60);

        System.out.println("Minimum: " + Collections.min(numbers));
        System.out.println("Maximum: " + Collections.max(numbers));
    }
}

Output:

Minimum: 10
Maximum: 80

These methods examine the collection and typically require O(n) time. Calling them on an empty collection throws NoSuchElementException.

16. Reversing a List

The Collections.reverse() method reverses the current order of a list. It does not sort the values in descending order unless the list was already sorted in ascending order.

List<String> names =
        new ArrayList<>(List.of("Amit", "Neha", "Priya"));

Collections.reverse(names);

System.out.println(names);

Output:

[Priya, Neha, Amit]

To obtain descending natural order, sort using Collections.reverseOrder(). Use Collections.reverse() when you specifically need to reverse the list's existing sequence.

17. Shuffling a List

The Collections.shuffle() method randomly permutes the elements of a list. It can be useful for quizzes, card games, randomized practice questions, or selecting an order for a simple demonstration.

List<String> questions =
        new ArrayList<>(List.of("Q1", "Q2", "Q3", "Q4", "Q5"));

Collections.shuffle(questions);

System.out.println(questions);

The output order can vary each time the program runs.

For repeatable results in tests, provide a seeded random generator supported by your Java version. Do not rely on ordinary shuffling for security-sensitive randomness.

18. Counting Frequency of Elements

The Collections.frequency() method counts how many elements in a collection are equal to a specified value.

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class FrequencyExample {
    public static void main(String[] args) {
        List<String> fruits =
                Arrays.asList("Apple", "Mango", "Apple", "Banana", "Apple");

        int count = Collections.frequency(fruits, "Apple");

        System.out.println("Apple appears: " + count + " times");
    }
}

Output:

Apple appears: 3 times

This method is useful for simple occurrence counting. For counts of many different values, a Map can be more suitable because it allows you to maintain counts as you process the data.

19. Swapping Elements in a List

The Collections.swap() method exchanges the elements at two specified indexes. The indexes must be valid for the list.

List<Integer> numbers =
        new ArrayList<>(List.of(10, 20, 30, 40));

Collections.swap(numbers, 0, 3);

System.out.println(numbers);

Output:

[40, 20, 30, 10]

This method is useful in simple rearrangement tasks and algorithm demonstrations.

20. Practical Example: Sorting and Searching Student Marks

Suppose a school application stores student marks. The program needs to sort marks in ascending order, find a particular mark, and report the minimum and maximum values.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class StudentMarksManager {
    public static void main(String[] args) {
        List<Integer> marks =
                new ArrayList<>(List.of(78, 92, 65, 88, 74, 92));

        Collections.sort(marks);
        System.out.println("Sorted marks: " + marks);

        int target = 88;
        int index = Collections.binarySearch(marks, target);

        if (index >= 0) {
            System.out.println(target + " found at index " + index);
        } else {
            System.out.println(target + " was not found");
        }

        System.out.println("Lowest mark: " + Collections.min(marks));
        System.out.println("Highest mark: " + Collections.max(marks));
        System.out.println("Count of 92: " + Collections.frequency(marks, 92));
    }
}

Sample output:

Sorted marks: [65, 74, 78, 88, 92, 92]
88 found at index 3
Lowest mark: 65
Highest mark: 92
Count of 92: 2

Because the list contains duplicate marks, binary search guarantees that a matching index is returned but does not guarantee which matching duplicate will be selected.

21. Common Errors and Troubleshooting

Problem Cause Solution
Binary search returns an unexpected negative value. The target is absent, or the list is not ordered as required. Sort using the correct ordering before searching and decode negative results when needed.
ClassCastException Elements are not mutually comparable, or an incompatible search key is supplied. Use compatible element types and a suitable comparator.
UnsupportedOperationException The list does not support the modifications needed for sorting or reversing. Copy it into a modifiable list such as new ArrayList<>(source).
IndexOutOfBoundsException An invalid index was supplied to swap() or another indexed operation. Check that indexes are between zero and list.size() - 1.
NoSuchElementException min() or max() was called on an empty collection. Check whether the collection is empty first.
Unexpected text order. String natural ordering is case-sensitive. Use a comparator such as String.CASE_INSENSITIVE_ORDER when appropriate.

22. Best Practices for Sorting and Searching

  • Always sort a list before using Collections.binarySearch().
  • Use the same comparator for sorting and searching.
  • Choose natural ordering when it clearly represents the required order.
  • Use a custom Comparator for sorting objects by business-specific fields.
  • Use Collections.reverseOrder() for descending natural ordering rather than confusing sorting with reversing.
  • Check for empty collections before calling min() or max().
  • Use a modifiable list when a utility method needs to change its elements.
  • Remember that sorting, reversing, shuffling, and swapping modify the supplied list.
  • For case-insensitive or locale-aware text ordering, choose the comparator or collation strategy that matches the application's requirements.
  • For repeated searches, consider whether maintaining sorted data is worth the cost of inserting and updating elements.
  • Do not assume binary search returns the first occurrence when duplicate values exist.

23. Practice Exercises

  1. Create a list of ten integers and sort it in ascending order.
  2. Sort a list of city names in descending natural order.
  3. Sort a list of strings by their length and use alphabetical order to break ties.
  4. Search for a number in a sorted list using Collections.binarySearch().
  5. Search for a missing number and calculate its insertion point from the negative result.
  6. Create an Employee class and sort employees by salary from highest to lowest.
  7. Find the minimum and maximum values in a collection of product prices.
  8. Reverse a list and compare the result with sorting the same list in descending order.
  9. Count how many times a chosen word appears in a list.
  10. Shuffle a list of quiz questions and display the resulting order.

24. Mini Project: Product Price Organizer

Project objective: Build a small Java program that stores product prices, sorts them, searches for a price, and displays useful statistics.

Requirements

  • Create an ArrayList<Integer> containing sample product prices.
  • Display the original list of prices.
  • Sort the prices in ascending order.
  • Sort the prices in descending order using Collections.reverseOrder().
  • Search for a given price using binary search after sorting in the matching order.
  • Display the minimum and maximum prices.
  • Count how many products have the same price.
  • Handle empty input before finding minimum or maximum values.

Expected Skills

After completing this project, learners should be able to combine Java lists, sorting utilities, comparators, binary search, and collection statistics in a practical program.

25. Interview Questions and Answers

Q1. What is the Collections class in Java?

Answer: Collections is a utility class in java.util that provides static methods for operations such as sorting, searching, reversing, shuffling, and finding minimum and maximum elements.

Q2. What is the difference between Collection and Collections?

Answer: Collection is an interface that represents a group of objects. Collections is a utility class that provides static methods for operating on collection objects.

Q3. How do you sort a list in Java?

Answer: Use Collections.sort(list) for natural ordering or Collections.sort(list, comparator) for custom ordering. You can also use list.sort(comparator).

Q4. How can you sort a list in descending order?

Answer: Use Collections.sort(list, Collections.reverseOrder()) for descending natural ordering of mutually comparable elements.

Q5. What is binary search?

Answer: Binary search finds a target by repeatedly dividing a sorted search range into halves. It can achieve logarithmic search time on random-access lists.

Q6. Why must a list be sorted before binary search?

Answer: Binary search relies on the ordering of the elements to decide which half to search next. Without the required ordering, the result is undefined.

Q7. What does binarySearch() return if an element is not found?

Answer: It returns -(insertion point) - 1. The insertion point is where the target could be inserted without breaking the required order.

Q8. Can binary search find duplicate elements?

Answer: It can return an index of a matching element, but it does not guarantee which matching index is returned when duplicates exist.

Q9. What is the difference between reverse() and reverseOrder()?

Answer: Collections.reverse(list) reverses the current element sequence. Collections.reverseOrder() provides a comparator for sorting in reverse natural order.

Q10. What is a Comparator?

Answer: A Comparator defines a comparison rule that can be used to sort objects according to fields or business requirements without requiring the class to define that ordering as its natural order.

Q11. What is the time complexity of binary search?

Answer: It is typically O(log n) for random-access lists such as ArrayList. For large linked lists, element traversal can make the overall operation linear in the number of links traversed.

Q12. What happens when Collections.min() is used on an empty collection?

Answer: It throws NoSuchElementException. Check that the collection contains elements before calling min() or max().

26. Quick Revision

  • Collections.sort(list) sorts using natural ordering.
  • Collections.sort(list, comparator) sorts using a custom ordering.
  • Collections.reverseOrder() supplies reverse natural ordering.
  • Collections.binarySearch(list, key) searches a correctly sorted list.
  • A non-negative binary search result indicates a match; a negative result encodes the insertion point.
  • Collections.min() and Collections.max() find extreme values.
  • Collections.reverse() reverses the current order.
  • Collections.shuffle() randomly permutes elements.
  • Collections.frequency() counts matching elements.
  • Collections.swap() exchanges two indexed elements.
  • Sorting and searching must use compatible comparison rules.

27. Conclusion

Sorting and searching are essential operations when working with Java collections. The Collections utility class provides convenient methods for sorting lists, searching sorted data, reversing and shuffling elements, and calculating basic collection statistics. By understanding natural ordering, custom comparators, binary search requirements, and common exceptions, developers can write clearer and more reliable Java programs.

Practice these methods with numbers, strings, and custom objects to strengthen your understanding of the Java Collections Framework.


Learn More with JustAcademy

Explore the Core Java Training Course to continue learning Java fundamentals, object-oriented programming, collections, exception handling, and other core concepts.

Interested in a course demonstration? Register for a Course Demo.

You can also visit the JustAcademy official website to explore available training programs.

Previous Next
whatsapp